/*
# MIAHX© 框架消息 FastDDS API 的包装类（C++端）

Version: 0.4.10,
Last updated: October 16, 2024

## Contributor(s)
* YAO Naiming <[naiming@iscas.ac.cn](mailto:naiming@iscas.ac.cn)>

## Change log
### v0.4.10
- .19: [新增] 迁移实现，重命名，新增注释，修复 get_stream_handler 实现缺陷

---
Copyright © 2024-2025 MIAHX Contributors, ISCAS, and ASIC. All Rights Reserved.
Licensed under Apache-2.0.
*/

#include "../include/miahx_cpp_wrapper"


/**
 * @brief 数据流处理器（C++接口）
 */
class BngClassicalStreamHandler : public StreamHandler {
public:
    explicit BngClassicalStreamHandler(Participant *participant)
            : mReader(nullptr) {
        data_listener listener = std::bind(&BngClassicalStreamHandler::on_data_available, this, std::placeholders::_1);
        mReader = std::make_unique<BngClassicalStreamReader>(participant, listener, nullptr);
    }

    string next_as_json_str() override {
        json data = json::object();
        string jstr;
        mMutex.lock();
        if (!mDataFrameQueue.empty()) {
            data = mDataFrameQueue.front();
            mDataFrameQueue.pop();
            jstr = data.dump();
        }
        mMutex.unlock();
        return jstr;
    }

    json next() override {
        json data = json::object();
        mMutex.lock();
        if (!mDataFrameQueue.empty()) {
            data = mDataFrameQueue.front();
            mDataFrameQueue.pop();
        }
        mMutex.unlock();
        return data;
    }

    void set_callback(const stream_callback& callback) override {
        if (nullptr != callback) {
            mCallback = callback;
        }
    }

private:
    void on_data_available(void *ptr) {
        auto frame = (BngClassicalDataFrame *) ptr;
        json jsamples = json::array();
        auto &hdr = frame->header();
        auto &source = hdr.header().source();
        auto &samples = frame->samples();
        for (auto iter = samples.begin(); iter != samples.end(); iter++) {
            auto jsample = json::object();
            jsample["isn"] = iter->iid();
            jsample["timestamp"] = iter->uts();
            jsample["veh_id"] = iter->veh_id();
            jsample["veh_name"] = iter->veh_name();
            jsample["veh_annotation"] = iter->veh_annotation();
            jsample["state_pos"] = iter->state_pos();
            jsample["state_dir"] = iter->state_dir();
            jsample["state_up"] = iter->state_up();
            jsample["state_front"] = iter->state_front();
            jsample["state_rotation"] = iter->state_rotation();
            jsample["state_vel"] = iter->state_vel();
            jsample["ecu_wheelspeed"] = iter->ecu_wheelspeed();
            jsample["ecu_gear"] = iter->ecu_gear();
            jsample["ecu_trip"] = iter->ecu_trip();
            jsample["road_speed_limit"] = iter->road_speed_limit();
            jsamples.push_back(jsample);
        }
        json jframe = json::object();
        jframe["source"] = source;
        jframe["samples"] = jsamples;

        if (nullptr != mCallback) {
            mCallback(jframe);
        } else {
            mMutex.lock();
            mDataFrameQueue.emplace(jframe);
            mMutex.unlock();
        }
    }

private:
    std::unique_ptr<BngClassicalStreamReader> mReader;
    std::recursive_mutex mMutex;
    std::queue<json> mDataFrameQueue;
    stream_callback mCallback;
};


shared_ptr<MiahxWrapper> MiahxWrapper::get_instance() {
    static shared_ptr<MiahxWrapper> instance(new MiahxWrapper());
    return instance;
}

MiahxWrapper::MiahxWrapper()
        : mParticipant(new Participant()) {}

StreamHandler &MiahxWrapper::get_stream_handler(const std::string &name) {
    auto found = mHandlers.find(name);
    if (found != mHandlers.end()) {
        return *found->second;
    } else {
        const string& key(name);
        shared_ptr<StreamHandler> handler;
        if ("vcls" == key) {
            handler = std::make_shared<BngClassicalStreamHandler>(mParticipant.get());
        }
        if (nullptr == handler) {
            throw std::exception("name should be \"vcls\"");
        }
        auto ret = mHandlers.insert(make_pair(name, handler));
        assert(ret.second);
        return *ret.first->second;
    }
}

void MiahxWrapper::set_stream_listener(const std::string &name, const stream_callback& callback) {
    auto handler_iter = mHandlers.find(name);
    if (handler_iter == mHandlers.end()) {
        throw std::exception("please call get_stream_handler(name) first");
    }
    auto found = mListeners.find(name);
    if (found == mListeners.end()) {
        auto ret = mListeners.insert(make_pair(name, callback));
        assert(ret.second);
        handler_iter->second->set_callback(callback);
    }
}
